package org.micode.demo.web.service;

import org.micode.common.codec.TokenCodec;
import org.micode.common.config.ApplicationConfig;
import org.micode.common.enums.OperationModeEnum;
import org.micode.common.exception.VerifyFailException;
import org.micode.common.helper.I18nMsgHelper;
import org.micode.demo.biz.base.BaseLoginService;
import org.micode.demo.db.cache.user.ISysUserCacheHandler;
import org.micode.demo.biz.service.BizSysUserService;
import org.micode.demo.biz.vo.SysUserVO;
import org.micode.demo.db.cache.user.SysUserCache;
import org.micode.demo.db.domain.dto.LogSysDTO;
import org.micode.demo.db.domain.dto.SysUserDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class LoginService extends BaseLoginService {

    @Autowired
    private BizSysUserService bizSysUserService;

    @Autowired
    private ISysUserCacheHandler sysUserCacheHandler;

    @Autowired
    private LogSysService logSysService;

    @Autowired
    private SysClientService sysClientService;

    public SysUserCache loginForTest(SysUserVO userVO) {
        SysUserDTO theUser = bizSysUserService.loginForTest(userVO);
        if (null == theUser) {
            throw new VerifyFailException(I18nMsgHelper.get("valid.user.not-found"));
        }
        return getLogonUserAuthCache(theUser, userVO.getLoginApp(), userVO.getLoginIp());
    }

    public SysUserCache loginByAccount(SysUserVO userVO) {
        validateImageCode(userVO.getUuid(), null, userVO.getImageCode());
        validateLoginApp(userVO.getLoginApp());
        return getLogonUserAuthCache(
                bizSysUserService.loginByAccount(userVO),
                userVO.getLoginApp(),
                userVO.getLoginIp());
    }

    private void validateLoginApp(String loginAppCode) {
        if (!sysClientService.findByCode(loginAppCode)) {
            log.warn(I18nMsgHelper.get("valid.clientApp.not-access") + "({})", loginAppCode);
            throw new VerifyFailException(I18nMsgHelper.get("valid.clientApp.not-access"));
        }
    }

    private SysUserCache getLogonUserAuthCache(SysUserDTO theUser, String loginApp, String loginIp) {
        if (null == theUser) {
            return null;
        }

        SysUserCache ret = theUser.toUserAuthCache();
        ret.setRetentionSeconds(bizSysConfigService.getUserTokenRetentionSeconds());
        ret.setToken(TokenCodec.newToken());
        ret.setLastLoginTime(System.currentTimeMillis());
        ret.setLoginApp(loginApp);
        ret.setLoginIp(loginIp);

        sysUserCacheHandler.setByKey(ret.getToken(), ret);

        logLogin(ret, loginIp);

        return ret;
    }

    public Boolean userLogout(String token, String remoteIp) {
        // 从 token 获取到UserCache
        SysUserCache cache = sysUserCacheHandler.getByKey(token);
        try {
            return bizSysUserService.userLogout(cache);
        } finally {
            sysUserCacheHandler.deleteByKey(token);
            logLogout(cache, remoteIp);
        }
    }

    private void logLogout(SysUserCache userCache, String remoteIp) {
        logRecord(userCache, I18nMsgHelper.get("api.syslog.sysUser.logout"),
                "/logout", remoteIp);
    }

    private void logLogin(SysUserCache userCache, String remoteIp) {
        logRecord(userCache, I18nMsgHelper.get("api.syslog.sysUser.login.ok"),
                "/login", remoteIp);
    }

    private void logRecord(SysUserCache userCache,
                           final String operation,
                           final String methodName,
                           final String remoteIp) {
        if (null == userCache) {
            log.warn(I18nMsgHelper.get("warn.syslog.record.fail.for-null-user"));
            return ;
        }

        try {
            logSysService.insert(new LogSysDTO() {{
                setUserId(userCache.getUserId());
                setUserType(userCache.getUserType());
                setOperationMode(OperationModeEnum.NORMAL.getCode());
                setOperation(operation);
                setMethod(methodName);
                setConsumeMs(0L);
                setOriginateIp(remoteIp);
                setOriginateModule(ApplicationConfig.MODULE_ID);
                setOriginateApp(null == userCache.getLoginApp()
                        ? ApplicationConfig.SERVICE_NAME
                        : userCache.getLoginApp());
                setUpdUser(getUserId());
                setUpdIp(getOriginateIp());
                setUpdProg(getOriginateApp());
            }});
        } catch (Exception e) {
            log.warn(I18nMsgHelper.get("warn.syslog.save.fail"), e);
        }
    }

}
